"""
Copyright 2012 Jorge Novaes Jr.
Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
"""

import math
import time
import random
import NinjaWarzLib as comm
import NinjaWarzBotGui as gui
import traceback
import sys

def getNextEnemy():

    stage = comm.getStage()

    #searching bosses to fight
    if options["fightBosses"] == True:
        if "small_girl" in stage["bosses"]:
            return "small_girl"
        elif "girl" in stage["bosses"]:
            return "girl"
        elif "genbu" in stage["bosses"]:
            return "genbu"
        elif "mechagenbu" in stage["bosses"]:
            return "mechagenbu"

    #searching udead horde to fight
    if options["fightHorde"] == True and "horde_in" in stats and stats["horde_in"] == 0:
        return "horde"

    #defining level search range
    seq = 1
    if options["fromLevel"] > options["toLevel"]:seq = -1

    for i in range(options["fromLevel"], options["toLevel"]+seq, seq):
        opponents = comm.getOpponents(i)
        for opponent in opponents:
            if "cid" in opponent:
                if opponent["cid"] in beatenBy:
                    continue #skip player tha beated me
                if options["enemy"] == "npc" and not ("random" in opponent):
                    return opponent["cid"]
                elif options["enemy"] == "player" and ("random" in opponent):
                    return opponent["cid"]
                elif options["enemy"] == "all":
                    return opponent["cid"]                
    return ""

def printStats():
    print "Player %s - lv.%s" % (stats["name"], stats["level"])
    printCurrency()
    printHp()
    printXp()
    
def printXp():
    levelExp = int(stats["total_exp_to_level"]) - int(stats["exp_to_level"])
    totalLevelExp = float(stats["total_exp_to_level"])    
    print "XP: %.0f%% - %d/%d" % (float(levelExp/totalLevelExp)*100, levelExp, totalLevelExp)

def printCurrency():
    print "Karma: %s, Money: %s, Tokens: %s" % (stats["karma"],stats["gold"],stats["gift_currency"])
    
def printHp():
    hp = getHp()
    print "HP: %.0f%% - %d/%d" % (hp["percentage"], hp["current"], hp["total"])

def getHp():
    hp = {"current":0, "total":0, "percentage":0}
    
    for ninja in stats["ninjas"]:
        hp["current"] = hp["current"] + int(ninja["health"])
        hp["total"] = hp["total"] + int(ninja["modified_max_health"])
        hp["percentage"] = float(hp["current"])/hp["total"]*100
    return hp

def healIfHPLowerThan(percentage):
    updateStats()
    hp = getHp()
    if hp["percentage"] < percentage:
        print "Healing player"
        response = comm.heal()
        if response["result"] == "success":
            print "   Gold spent in heal: %d"% (response["gold_spent"])
        else:
            print "   "+response["error"]
    
def fight(player):

    if player == "horde":
        print "Fighting undead horde..."
    elif player == "small_girl":
        print "Fighting small girl..."
    elif player == "genbu":
        print "Fighting genbu..."
        
    #fighting
    result = comm.fight(player)

    #if ninjas are tired, sleep and try again
    while "error" in result:
        print result["error"]
        print "Resting..."
        time.sleep(3)
        result = comm.fight(player)

    #comm.prettyPrintJson(result)    
    #fight result
    if player == "horde":
        print "   Killed %d zombies, won %d gold and %d xp" % (result["spoils"]["kills"],result["spoils"]["gold"],result["spoils"]["exp"])
        return ""
    elif player == "genbu":
        comm.prettyPrintJson(result)
        return ""
    else:
        print "%s lv.%s vs %s lv.%s => %s %s" % (result["me"]["name"], result["me"]["level"], result["opponent"]["name"], result["opponent"]["level"], result["me"]["name"], result["result"])
        if result["result"] == "win":
            print "Looted %s gold, %s xp and %d item" % (result["spoils"]["gold"], result["spoils"]["exp"], len(result["spoils"]["items"]))
        elif result["result"] == "loss":
            beatenBy.append(result["opponent"]["cid"])

    #print "Resting..."
    #time.sleep(3)

    return result["spoils"]["items"]

def updateStats():
    global stats
    stats = comm.getMyStats()

def farm():
    #getting my stats
    updateStats()
    printStats()
    
    #assist on ally (if any...)
    if options["assistAlly"] == True: assistAlly()

    #gold cloud!
    #if stats["cloud"] == 0:
        
        
    #check hp
    healIfHPLowerThan(options["healIfLower"])
    
    #fight in tournament
    if "tournament_in" in stats and stats["tournament_in"] == 0:
        fightTournament()
        
    enemy = getNextEnemy()
    while enemy == "": #couldn't find anyone... sleep a little
        print "Waiting enemy respawn..."
        time.sleep(5)
        #npc = getLowestNPC(0)
        enemy = getNextEnemy()

    #fighting
    loot = fight(enemy)

    #checking loot
    if len(loot) > 0: #if has loot
        for item in loot: 
            if options["sellKarmaWeapons"] == True and item["karma_value"] <> "0": #has karma value!!!

                print "Selling karma weapons"
                soldData = comm.sellItem(item["iid"])
                if soldData["result"] == "success":
                    print "   Sold %s for %s karma" % (item["name"], soldData["sold_for"])
                else:
                    print "   Error: %s" % (soldData["error"])
            elif item["type"] == "1": #got a weapon
                if options["autoEquipWeapons"] == True: autoEquipWeapons()
                if options["sellUnusedWeapons"] == True: sellUnusedWeapons()
                if options["sellFoodWeapons"] == True: sellFoodWeapons()
            elif item["type"] == "2": #got a relic
                sellRelics()
            else: #unknown item...
                print "Don't know what to do with: "
                comm.prettyPrintJson(item)

    print "-------------------------------------------"
    print ""

def autoEquipWeapons():
    updateStats()
    
    #ninja list ordered by ninja level with dps
    #nid, level, iid, dps
    ninjas = []
    for ninja in stats["ninjas"]:
        ninjas.append({"nid": ninja["nid"],
                      "name": ninja["name"],
                      "level": int(ninja["level"]),
                      "iid": ninja["weapon"]["iid"],
                      "weapon": ninja["weapon"]["name"],
                      "dps": 100*float(ninja["weapon"]["attributes"]["base_damage"])/float(ninja["weapon"]["attributes"]["base_speed"])})
    ninjasSorted = sorted(ninjas, key=lambda k: k["level"], reverse=True)

    #unequiped weapons sorted by dps
    weapons = []
    for item in stats["inventory"]:
        if item["type"] == "1":
            if "min_level" in item["attributes"] and item["attributes"]["min_level"] > stats["level"]: #dont add itens to the list taht I cant use
                continue
            else:
                weapons.append({"iid": item["iid"],
                                "name": item["name"],
                                "dps": 100*float(item["attributes"]["damage"])/float(item["attributes"]["speed"])
                                })
    weaponsSorted = sorted(weapons, key=lambda k: k["dps"], reverse=True)

    print "Auto equipping weapons..."
    while True:
        changedWeapon = False
        for ninja in ninjasSorted:
            for weapon in weaponsSorted:
                if weapon["dps"] > ninja["dps"]:
                    #switch weapons
                    print "   Switching %s weapon '%s' %.1fDPS for '%s' %.1fDPS" % (ninja["name"], ninja["weapon"], ninja["dps"], weapon["name"], weapon["dps"])
                    comm.equip(ninja["nid"], weapon["iid"])

                    tempIid = ninja["iid"]
                    tempName = ninja["weapon"]
                    tempDps = ninja["dps"]

                    ninja["iid"] = weapon["iid"]
                    ninja["weapon"] = weapon["name"]
                    ninja["dps"] = weapon["dps"]

                    weapon["iid"] = tempIid
                    weapon["name"] = tempName
                    weapon["dps"] = tempDps

                    changedWeapon = True


            if changedWeapon == True:
                weaponsSorted = sorted(weaponsSorted, key=lambda k: k["dps"], reverse=True)                    
                      
        if changedWeapon == False: break
                            
def sellRelics():
    updateStats()
    relics = []

    #getting equiped relics.
    for relic in stats["relics"]:
        relics.append(relic["iid"])        

    print "Selling relics..."
    for item in stats["inventory"]:
        if item["type"] == "2": #found a relic
            if not "unsellable" in item["attributes"]: #if is possible to sell
                if options["sellRelics"] == "unequipped": relics.append(item["iid"])
                if item["iid"] in relics: #doubled one
                    #sell relic
                    soldData = comm.sellItem(item["iid"])
                    if soldData["result"] == "success":
                        print "   Sold %s for %s gold" % (item["name"], soldData["sold_for"])
                    else:
                        print "   Error: %s" % (soldData["error"])
                else:
                    relics.append(item["iid"])
    
def sellUnusedWeapons():
    updateStats() 

    print "Selling unused weapons..."
    for item in stats["inventory"]:
        if item["type"] == "1": #found a weapon
            if not "unsellable" in item["attributes"]: #if is possible to sell
                if item["iid"] != "185" and item["iid"] != "186": #not food
                    #if item minimum level is higher than me, leave it alone
                    if "min_level" in item["attributes"] and item["attributes"]["min_level"] > stats["level"]:
                        continue
                    else:
                        #print "   Selling %s" % (item["name"])
                        soldData = comm.sellItem(item["iid"])
                        if soldData["result"] == "success":
                            print "   Sold %s for %s gold" % (item["name"], soldData["sold_for"])
                        else:
                            print "   Error: %s" % (soldData["error"])
                            break
                    
def sellFoodWeapons():
    updateStats() 

    print "Selling food weapons..."
    for item in stats["inventory"]:
        if item["iid"] == "185" or item["iid"] == "186": #food
            #print "   Selling %s" % (item["name"])
            soldData = comm.sellItem(item["iid"])
            if soldData["result"] == "success":
                print "   Sold %s for %s gold" % (item["name"], soldData["sold_for"])
            else:
                print "   Error: %s" % (soldData["error"])

def assistAlly():
    updateStats()

    for ally in stats["allies"]:
        #comm.prettyPrintJson(ally)
        if ally["needs_assistance"] == 1:
            result = comm.assistAlly(ally["cid"], random.randint(0, 3), random.choice("ABC"))
            if result["result"] == "success":
                print "Assited ally %s for %d gold and %d xp" % (ally["name"], result["spoils"]["gold"], result["spoils"]["exp"])
            else:
                print result["error"]
            return

def fightTournament():
    if int(stats["level"]) < 5: return #too low level to enter tournaments
    
    print "Fighting in tournament..."
    #find the best weapon
    prizesList = []
    for prize in comm.getTournamentPrizes():
        prizesList.append(100*float(prize["attributes"]["damage"])/float(prize["attributes"]["speed"]))

    bestPrizePos = 0
    for i, prize in enumerate(prizesList):
        if prizesList[i] > prizesList[bestPrizePos]:
            bestPrizePos = i

    if bestPrizePos % 2 == 0:
        tournamentType = "same_level"
    else:
        tournamentType = "open"
        
    tournamentSize = int(bestPrizePos / 2) + 4

    print "   Best prize dps %.1f, tournament type %s, tournament size %d" % (prizesList[bestPrizePos], tournamentType, tournamentSize)

    tourney = comm.createTournament(tournamentType, tournamentSize)

    for i in range(1, tournamentSize+1):
        result = comm.fightInTournament(tourney["data"]["tid"])
        print "   tournament fight %d of %d: %s" % (i, tournamentSize, result["result"])
        if result["result"] != "win": break
        
    if result["result"] == "tournament_win":
        #comm.prettyPrintJson(result)
        print "   Won %s and %d xp" % ( result["spoils"]["items"][0]["name"], result["spoils"]["exp"] )
        if options["autoEquipWeapons"] == True: autoEquipWeapons()
        if options["sellUnusedWeapons"] == True: sellUnusedWeapons()
        if options["sellFoodWeapons"] == True: sellFoodWeapons()
    else:
        print "   lost to player '%s' lv.%s" % ( result["opponent"]["name"], result["opponent"]["level"])

    
    


    
#################################################


beatenBy = []
options = {
    "enemy": gui.fightEnemyTypeVar.get(),
    "fromLevel": gui.fightFromLevelVar.get(),
    "toLevel": gui.fightToLevelVar.get(),
    "healIfLower": gui.healIfLowerVar.get(),
    "assistAlly": gui.assitAlliesVar.get(), 
    "fightHorde": gui.fightHordeVar.get(),
    "fightBosses": gui.fightBossesVar.get(),
    "fightTournament": gui.fightTournamentVar.get(),
    "getDaimyoBonus": gui.getDaimyoBonusVar.get(), 
    "autoEquipWeapons": gui.autoEquipWeaponsVar.get(),
    "sellUnusedWeapons": gui.sellUnusedWeaponsVar.get(),
    "sellKarmaWeapons": gui.sellKarmaWeaponsVar.get(),
    "sellFoodWeapons": gui.sellFoodWeaponsVar.get(),
    "sellRelics": "duplicated", #duplicated, unequipped, none
    }

def getPhpSessId():
    stats = comm.init()
    gui.phpSessIdVar.set(comm._sessionId)

gui.getPhpSessIdButton.config(command=getPhpSessId)

gui.root.mainloop()



"""
try:
    if options["autoEquipWeapons"]: autoEquipWeapons()
    while True: farm()
except KeyboardInterrupt:
    print "Shutdown requested...exiting"
except Exception:
    print traceback.print_exc()
    print ">>> Time error occurred: %s" % (time.strftime("%a, %d %b %Y %H:%M", time.localtime()))
    sys.exit(0)
"""



